package com.jddai.arithmetic;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class PSO_Model {

    private ArrayList<ArrayList<Double>> Model;
    private ArrayList<ArrayList<Double>> Data;
    private ArrayList<Double> uscale;
    private int maxgen = 100;
    private int sizepop = 20;

    private ArrayList<Double> ub = new ArrayList<>();
    private ArrayList<Double> lb = new ArrayList<>();

    private ArrayList<Double> Vmax = new ArrayList<>();
    private ArrayList<Double> Vmin = new ArrayList<>();
    private ArrayList<ArrayList<ArrayList<Double>>> V = new ArrayList<>();

    private Double zbestfitness = 0.0; //全局最佳
    private ArrayList<ArrayList<Double>> zbest = new ArrayList<>(); //全局最佳的brb

    private ArrayList<Double> gbestfitness = new ArrayList<>(); //个体最佳
    private ArrayList<ArrayList<ArrayList<Double>>> gbest = new ArrayList<>(); //个体最佳的brb

    private ArrayList<ArrayList<ArrayList<Double>>> pop = new ArrayList<>();


    private int c1 = 2;
    private int c2 = 2;

    public PSO_Model(ArrayList<ArrayList<Double>> Model, ArrayList<ArrayList<Double>> Data, ArrayList<Double> uscale){
        this.Model = Model;
        this.Data = Data;
        this.uscale = uscale;
    }

    public Double fitness(ArrayList<ArrayList<Double>> Data, ArrayList<ArrayList<Double>> single_pop) throws IOException {
        ArrayList<Double> Fitness;

        BRBInference BRB = new BRBInference(uscale, Data, single_pop);
        BRB.attr_identify();
        BRB.fuse();

        ArrayList<Double> real_output = new ArrayList<>();
        for(int i=0; i<Data.size();i++){
            real_output.add(Data.get(i).get(Data.get(i).size()-1));
            System.out.println(Data.get(i).get(Data.get(i).size()-1));
        }

        Fitness = BRB.getInference_Result();
        double sum=0.0;
        for(int i=0; i<Fitness.size();i++){
            sum += BRBInference.abs(Fitness.get(i)-real_output.get(i));
        }
        double avg = sum/Fitness.size();

        return avg;
    }

    public void Init() throws IOException {
        lb.add(0.0);
        for(int i=1; i<1+16;i++){
            lb.add(Model.get(0).get(i));
            //System.out.println(Model.get(0).get(i));
        }
        lb.add(0.0);
        lb.add(0.0);
        lb.add(0.0);
        lb.add(0.0);
        lb.add(0.0);

        ub.add(1.0);
        for(int i=1; i<1+16;i++){
            ub.add(Model.get(Model.size()-1).get(i));
            //System.out.println(Model.get(Model.size()-1).get(i));
        }
        ub.add(1.0);
        ub.add(1.0);
        ub.add(1.0);
        ub.add(1.0);
        ub.add(1.0);

        for(int i=0;i<ub.size();++i) {
            Vmax.add((ub.get(i) - lb.get(i))*0.5);
            Vmin.add(-(ub.get(i) - lb.get(i))*0.5);
        }

        for(int k=0; k<sizepop; k++){
            ArrayList<ArrayList<Double>> Temp = new ArrayList<>();
            for(int i=0; i<Model.size();i++){
                ArrayList<Double> temp = new ArrayList<Double>();
                for(int j=0; j<Model.get(i).size();j++){
                    temp.add(Model.get(i).get(j));
                }
                Temp.add(temp);
            }
            pop.add(Temp);
        }

        for(int i=0; i<pop.size();i++){    //初始速度
            ArrayList<ArrayList<Double>> Temp = new ArrayList<>();
            for(int j=0; j<pop.get(i).size()-2; j++){
                ArrayList<Double> temp = new ArrayList<>();
                for(int k=0; k<pop.get(i).get(j).size(); k++){
                    double tmp = new Random().nextDouble();
                    double value = (ub.get(k) - lb.get(k))*tmp *0.5;
                    temp.add(value);
                }
                Temp.add(temp);
            }
            V.add(Temp);
        }


        for(int i=0; i<pop.size();i++){ //初始种群
            for (int j=0; j<pop.get(i).size()-2;j++){
                for(int z=0; z<pop.get(i).get(j).size(); z++){
                    double tmp = new Random().nextDouble();
                    double value = (ub.get(z) - lb.get(z))*tmp+lb.get(z);
                    if(value > ub.get(z)){
                        value = ub.get(z);
                    }
                    if(value < lb.get(z)){
                        value = lb.get(z);
                    }
                    pop.get(i).get(j+1).set(z,value);
                }
            }
        }

        ArrayList<Double> mseList = new ArrayList<>();
        for(int k=0; k<pop.size();k++){
            double mse = fitness(Data, pop.get(k));
            mseList.add(mse);
        }

        System.out.println();


    }

}
